﻿using System;
using System.Globalization;
using System.Text;
using Lucene.Net.Analysis;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Lucene.Linq.VSTests
{
    [TestClass] //[Description("Various unit tests from Lucene.Net.Test for exploring Lucene.Net implementation")]
    public class TestLucene
    {
        private static readonly string NDS = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;

        private readonly String[][]
            data = new[]
                       {
                           // tracer  contents         int            float                     string   custom   i18n                  long             double
                           new[]
                               {
                                   "A", "x a", "5", "4f", "c", "A-3", "p\u00EAche", "10",
                                   "-4" + NDS + "0"
                               },
                           new[]
                               {
                                   "B", "y a", "5", "3" + NDS + "4028235E38", "i", "B-10", "HAT",
                                   "1000000000", "40" + NDS + "0"
                               },
                           new[]
                               {
                                   "C", "x a b c", "2147483647", "1" + NDS + "0", "j", "A-2",
                                   "p\u00E9ch\u00E9", "99999999", "40" + NDS + "00002343"
                               },
                           //new System.String[]{   "D",   "y a b c",       "-1",          "0" + NDS + "0f",         "a",     "C-0",   "HUT",                System.Convert.ToString(System.Int64.MaxValue), System.Convert.ToString(System.Double.MinValue)}, 
                           //new System.String[]{   "E",   "x a b c d",     "5",           "2f",                     "h",     "B-8",   "peach",              System.Convert.ToString(System.Int64.MinValue), System.Convert.ToString(System.Double.MaxValue)}, 
                           new[]
                               {
                                   "D", "y a b c", "-1", "0" + NDS + "0f", "a", "C-0", "HUT",
                                   Convert.ToString(Int64.MaxValue), Double.MinValue.ToString("R")
                               }
                           ,
                           new[]
                               {
                                   "E", "x a b c d", "5", "2f", "h", "B-8", "peach",
                                   Convert.ToString(Int64.MinValue), Double.MaxValue.ToString("R")
                               }
                           ,
                           new[]
                               {
                                   "F", "y a b c d", "2", "3" + NDS + "14159f", "g", "B-1",
                                   "H\u00C5T", "-44", "343" + NDS + "034435444"
                               },
                           new[]
                               {
                                   "G", "x a b c d", "3", "-1" + NDS + "0", "f", "C-100", "sin",
                                   "323254543543", "4" + NDS + "043544"
                               },
                           new[]
                               {
                                   "H", "y a b c d", "0", "1" + NDS + "4E-45", "e", "C-88",
                                   "H\u00D8T", "1023423423005", "4" + NDS + "043545"
                               },
                           new[]
                               {
                                   "I", "x a b c d e f", "-2147483648", "1" + NDS + "0e+0", "d",
                                   "A-10", "s\u00EDn", "332422459999", "4" + NDS + "043546"
                               },
                           new[]
                               {
                                   "J", "y a b c d e f", "4", "" + NDS + "5", "b", "C-7", "HOT",
                                   "34334543543", "4" + NDS + "0000220343"
                               },
                           new[] {"W", "g", "1", null, null, null, null, null, null},
                           new[] {"X", "g", "1", "0" + NDS + "1", null, null, null, null, null},
                           new[] {"Y", "g", "1", "0" + NDS + "2", null, null, null, null, null},
                           new[] {"Z", "f g", null, null, null, null, null, null, null}
                       };


        private Searcher full;
        private Query queryA;
        private Query queryE;
        private Query queryF;
        private Query queryG;
        private Query queryX;
        private Query queryY;
        private Searcher searchX;
        private Searcher searchY;
        private Sort sort;

        private Searcher GetIndex(bool even, bool odd)
        {
            var indexStore = new RAMDirectory();
            var writer = new IndexWriter(indexStore, new SimpleAnalyzer(), true);
            for (int i = 0; i < data.Length; ++i)
            {
                if (((i%2) == 0 && even) || ((i%2) == 1 && odd))
                {
                    var doc = new Document();
                    doc.Add(new Field("tracer", data[i][0], Field.Store.YES, Field.Index.NO));
                    doc.Add(new Field("contents", data[i][1], Field.Store.NO, Field.Index.TOKENIZED));
                    if (data[i][2] != null)
                        doc.Add(new Field("int", data[i][2], Field.Store.NO, Field.Index.UN_TOKENIZED));
                    if (data[i][3] != null)
                        doc.Add(new Field("float", data[i][3], Field.Store.NO, Field.Index.UN_TOKENIZED));
                    if (data[i][4] != null)
                        doc.Add(new Field("string", data[i][4], Field.Store.NO, Field.Index.UN_TOKENIZED));
                    if (data[i][5] != null)
                        doc.Add(new Field("custom", data[i][5], Field.Store.NO, Field.Index.UN_TOKENIZED));
                    if (data[i][6] != null)
                        doc.Add(new Field("i18n", data[i][6], Field.Store.NO, Field.Index.UN_TOKENIZED));
                    if (data[i][7] != null)
                        doc.Add(new Field("long", data[i][7], Field.Store.NO, Field.Index.UN_TOKENIZED));
                    if (data[i][8] != null)
                        doc.Add(new Field("double", data[i][8], Field.Store.NO, Field.Index.UN_TOKENIZED));
                    doc.SetBoost(2); // produce some scores above 1.0
                    writer.AddDocument(doc);
                }
            }
            writer.Optimize();
            writer.Close();
            return new IndexSearcher(indexStore);
        }

        private Searcher GetFullIndex()
        {
            return GetIndex(true, true);
        }

        // make sure the documents returned by the search match the expected list
        private void AssertMatches(Searcher searcher, Query query, Sort sort, String expectedResult)
        {
            Hits result = searcher.Search(query, sort);
            var buff = new StringBuilder(10);
            int n = result.Length();
            for (int i = 0; i < n; ++i)
            {
                Document doc = result.Doc(i);
                String[] v = doc.GetValues("tracer");
                for (int j = 0; j < v.Length; ++j)
                {
                    buff.Append(v[j]);
                }
            }
            Assert.AreEqual(expectedResult, buff.ToString());
        }

        private Searcher GetXIndex()
        {
            return GetIndex(true, false);
        }

        private Searcher GetYIndex()
        {
            return GetIndex(false, true);
        }

        [TestInitialize]
        public void SetUp()
        {
            full = GetFullIndex();
            searchX = GetXIndex();
            searchY = GetYIndex();
            queryX = new TermQuery(new Term("contents", "x"));
            queryY = new TermQuery(new Term("contents", "y"));
            queryA = new TermQuery(new Term("contents", "a"));
            queryE = new TermQuery(new Term("contents", "e"));
            queryF = new TermQuery(new Term("contents", "f"));
            queryG = new TermQuery(new Term("contents", "g"));
            sort = new Sort();
        }

        [TestMethod]
        public void TestReverseSort()
        {
            sort.SetSort(new[] {new SortField(null, SortField.SCORE, true), SortField.FIELD_DOC});
            AssertMatches(full, queryX, sort, "IEGCA");
            AssertMatches(full, queryY, sort, "JFHDB");

            sort.SetSort(new SortField(null, SortField.DOC, true));
            AssertMatches(full, queryX, sort, "IGECA");
            AssertMatches(full, queryY, sort, "JHFDB");

            sort.SetSort("int", true);
            AssertMatches(full, queryX, sort, "CAEGI");
            AssertMatches(full, queryY, sort, "BJFHD");

            sort.SetSort("float", true);
            AssertMatches(full, queryX, sort, "AECIG");
            AssertMatches(full, queryY, sort, "BFJHD");

            sort.SetSort("string", true);
            AssertMatches(full, queryX, sort, "CEGIA");
            AssertMatches(full, queryY, sort, "BFHJD");
        }
    }
}